#include <iostream>
#include <sys/select.h>
#include <poll.h>
#include "Sock.hpp"

using namespace std;

#define FD_NONE -1

class PollServer
{
public:
    static const int _nfds = 100; // 用户自行定义：同时能管理的fd个数
    PollServer(const uint16_t port = 8080) : _port(port)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "%s", "init PollServer success\n");

        _fds = new struct pollfd[_nfds];
        for (int i = 0; i < _nfds; i++)
        {
            _fds[i].fd = FD_NONE;
            _fds[i].events = _fds[i].revents = 0;
        } // 初始化该结构体数组

        _fds[0].fd = _listensock;
        _fds[0].events = POLL_IN; // 添加套接字读事件
    }
    void Start()
    {
        int timeout = -1;
        while (true)
        {
            int n = poll(_fds, _nfds + 1, timeout); // poll

            switch (n)
            {
            case 0: // 超时
                logMessage(DEBUG, "%s\n", "poll timeout");
                break;
            case -1: // poll出错
                logMessage(WARNING, "%s\n", "poll error");
                break;
            default: // 获取到新连接/新请求
                handleEvent();
                break;
            }
        }
    }
    ~PollServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_fds)
            delete[] _fds;
    }

private:
    void handleEvent() // 处理就绪事件
    {
        // 1.获取新连接
        if (_fds[0].revents & POLLIN)
        {
            Accept();
        }

        // 2.服务新请求
        for (int i = 1; i < _nfds; i++)
        {
            if (_fds[i].fd != FD_NONE && _fds[i].revents & POLL_IN)
            {
                Recver(i);
            }
        }
    }
    void Accept()
    {
        string cli_ip;
        uint16_t cli_port;
        int sock = Sock::Accept(_listensock, &cli_ip, &cli_port); // 此时获取连接，就不会阻塞了，因为poll已经等待过了
        logMessage(DEBUG, "get new connect[%s:%d]:%d", cli_ip.c_str(), cli_port, sock);

        int pos = 1;
        for (; pos < _nfds; pos++)
        {
            if (_fds[pos].fd == FD_NONE)
                break;
        }
        if (pos == _nfds) // 已经超过了能等待的fd数量(设置_nfds为更大)
        {
            logMessage(ERROR, "poll fd_array already full! close:%d", sock);
            close(sock);
        }
        else
        {
            _fds[pos].fd = sock;
            _fds[pos].events = POLL_IN;
        }
    }
    void Recver(int pos)
    {
        // 此时进行读取，必然不会阻塞
        int sock = _fds[pos].fd;
        char buffer[1024];
        ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
        // 这样读取，不能保证读到一个完整报文，需要定制应用层协议
        if (s > 0)
        {
            buffer[s] = 0;
            cout << sock << ":" << buffer;
        }
        else if (s == 0) // 客户端关闭,断开连接:也是一种IO，也会被poll检测到
        {
            // 关闭sock
            close(sock);
            // 从结构体数组中去掉这个sock
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
            logMessage(NORMAL, "client[%d] quit\n", sock);
        }
        else // 出错
        {
            logMessage(WARNING, "recv error\n");
        }
    }

private:
    uint16_t _port;
    int _listensock;

    struct pollfd *_fds; // 结构体数组
    // 该结构体内不同的成员变量，分别做输入和输出型参数，就不用每次都需要重新设定了
};